﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OxyPlot;

namespace AutoCorrelatorGUI.Model
{
   public class Well_Output
   {
      public Well_Output()
      {
         Data = new List<DataPoint>();
         DataStore = new Dictionary<int, double>();
         Stats = new WellStats();
      }

      public List<DataPoint> Data { get; private set; }

      public Dictionary<int, double> DataStore { get; private set; }

      public WellStats Stats { get; private set; }

      public void ProcessInput(Well_Input input, NormalizationTypes normMethod, bool calcDerivative)
      {
         Data.Clear();

         for (int i = 0; i < input.Data.Count; i++)
         {
            double yVal = input.Data[i].Y;

            switch (normMethod)
            {
            case NormalizationTypes.None: //Do nothing
               break;
            case NormalizationTypes.VarianceFunction:
               yVal /= input.VarianceFunction;
               break;
            case NormalizationTypes.Max:
               yVal /= input.Stats.Maximum;
               break;
            case NormalizationTypes.AbsMax:
               yVal /= Math.Abs(input.Stats.Maximum);
               break;
            case NormalizationTypes.Min:
               yVal /= input.Stats.Minimum;
               break;
            case NormalizationTypes.AbsMin:
               yVal /= Math.Abs(input.Stats.Minimum);
               break;
            case NormalizationTypes.Mean:
               yVal /= input.Stats.Mean;
               break;
            case NormalizationTypes.Sum:
               yVal /= input.Stats.Sum;
               break;
            case NormalizationTypes.StdDev:
               yVal /= input.Stats.StdDev;
               break;
            case NormalizationTypes.Variance:
               yVal /= input.Stats.Variance;
               break;
            case NormalizationTypes.Norm:
               yVal /= input.Stats.Norm;
               break;
            case NormalizationTypes.ZScore:
               yVal = (yVal - input.Stats.Mean) / input.Stats.StdDev;
               break;
            case NormalizationTypes.Normalized0to1:
               yVal = (yVal - input.Stats.Minimum) / (input.Stats.Maximum - input.Stats.Minimum);
               break;
            default:
               break;
            }

            Data.Add(new DataPoint(input.Data[i].X, yVal));
         }

         //Finally, if we are calculating the first derivative, that calc goes here
         if (calcDerivative)
         {
            List<DataPoint> deriv = CalcDerivative(Data);

            Data.Clear();

            foreach (var item in deriv)
            {
               Data.Add(new DataPoint(item.X, item.Y));
            }
         }

         //Sychronize the data store to match
         DataStore.Clear();

         foreach (var point in Data)
         {
            DataStore.Add((int)Math.Round(point.X), point.Y);
         }

         //Now finally update the diff stats
         Stats.Calc(Data);
      }

      private List<DataPoint> CalcDerivative(List<DataPoint> data)
      {
         //Clear temp vals and then copy all AutoCovData into the list again
         List<DataPoint> tempVals = new List<DataPoint>();

         for (int i = 0; i < data.Count; i++)
         {
            DataPoint left = data[i];
            DataPoint right = data[i];

            if (i != 0)
               left = data[i - 1];

            if (i != data.Count - 1)
               right = data[i + 1];

            double deriv = (right.Y - left.Y) / (right.X - left.X);

            tempVals.Add(new DataPoint(data[i].X, deriv));
         }

         return tempVals;
      }
   }
}
